import { INVALID_VALUE } from '../../../Core/CoreDefine';
import { MapWrap } from "../../../Core/FrameEx/ES5Ex";
import GParam from "../../../Core/GEvent/GParam";
import { GRunTime } from "../../../Core/Manager/DataPool";
import { BLESSEND_INFO, CMsg, ITEM_TYPE, SQUAD_BUTTON } from "../../Common/Define";
import { VIEW_ID } from '../../Common/UI';
import GameMgr from "../../Logic/GameMgr";
import { generateUid, JXDef } from './../../../conventions/JXCommon';
import { PRIORITY_DATA } from './../../../Core/CoreDefine';
import { GCtrl } from './../../../Core/GCtrl';
import { CURRENCY, KF, PART_GOODS, PART_ITEM } from './../../Common/Define';
import { REquireItem } from "./RunRaw/RItemAttach";
import RJXItem from './RunRaw/RJXItem';

const { ccclass } = cc._decorator;
@ccclass
export default class RBagData extends GRunTime {
    private _equipData: MapWrap<string, REquireItem> = null;
    // 物品索引
    protected _itemData: MapWrap<string, RJXItem[]> = new MapWrap<string, RJXItem[]>();


    onInit() {
        this.initEvent();
        this._equipData = new MapWrap<string, REquireItem>();
        this._itemData = new MapWrap<string, RJXItem[]>();
        this.initData();
    }


    protected initData() {
        GameMgr.lOwnEquips.getAllEquips().map((value: any) => {
            let insId = value[0];
            let equip = new REquireItem(value);
            this._equipData.set(insId, equip);
        })

        let object = GameMgr.lOwnItems.getAllItems();
        for (const key in object) {
            if (Object.prototype.hasOwnProperty.call(object, key)) {
                let items: RJXItem[] = []
                const element = object[key];
                element.forEach(item => {
                    let r = new RJXItem(item);
                    items.push(r)
                });
                this._itemData.set(key, items);
            }
        }

        if (GameMgr.lOwnItems.isFrist) {
            let coin = GameMgr.systemConfig.value(JXDef.SYS_CONFIG_KEY.basicGold)
            let jewel = GameMgr.systemConfig.value(JXDef.SYS_CONFIG_KEY.basicGem)
            this.getOrUseItem(new RJXItem([CURRENCY.YUSHI, ITEM_TYPE.CURRENCY, jewel]));
            this.getOrUseItem(new RJXItem([CURRENCY.GOLD, ITEM_TYPE.CURRENCY, coin]));
            this.saveItem();
            GameMgr.lOwnItems.isFrist = false;
        }

    }


    protected initEvent() {
        GCtrl.ES.on(CMsg.client.equip.onEquipPutOn, this, this.onPutOnEquip.bind(this), PRIORITY_DATA);
        GCtrl.ES.on(CMsg.client.equip.onEquipPutOff, this, this.onPutOffEquip.bind(this), PRIORITY_DATA);
        GCtrl.ES.on(CMsg.client.equip.onAddEquipSlv, this, this.onAddEquipSlv.bind(this), PRIORITY_DATA);
        GCtrl.ES.on(CMsg.client.bag.onBagItemChange, this, this.onBagItemChange.bind(this), PRIORITY_DATA);
        GCtrl.ES.on(CMsg.client.equip.ondelEquip, this, this.delEquip.bind(this), PRIORITY_DATA);
        GCtrl.ES.on(CMsg.client.equip.AddSynthesisEquip, this, this.AddSynthesisEquip.bind(this), PRIORITY_DATA);
    }
    /**共用 */
    /** 获取某个物品合并数量后的Item */
    public getMegreItems(id: number | RJXItem, type?: number | RJXItem): RJXItem {
        let items: RJXItem[];
        let out: RJXItem;

        if (typeof id == 'number') {
            if (typeof type == 'number') {
                items = this.getItems(id, type);
                out = new RJXItem([id, type, 0]);
            }
        }
        else {
            items = this.getItems(id.id, id.type);
            if (type && type instanceof RJXItem) {
                out = type;
            }
            else {
                out = new RJXItem([id.id, id.type, 0]);
            }
        }
        if (!items) return out;
        out.num = 0;
        for (let i = 0; i < items.length; i++) {
            out.num += items[i].num;
        }
        return out;
    }

    public getItems(id: number, type) {
        let key = KF.genItemKey(id, type);
        return this._itemData.get(key) || [];
    }
    /***************************************************道具部分************************************ */
    public get itemData() {
        return this._itemData;
    }

    /**存储道具 */
    protected saveItem() {
        GameMgr.lOwnItems.save(this._itemData);
    }

    protected onBagItemChange(_, items: number[][]) {
        // console.log("进入次数");

        if (typeof (items[0]) === "number") {
            cc.error("物品格式不正确，请确定业务逻辑")
            return
        }
        items.forEach(item => {
            let id = item[PART_GOODS.id];
            let type = item[PART_GOODS.type];
            switch (type) {
                case ITEM_TYPE.HERO: {
                    GCtrl.ES.emit(CMsg.client.hero.onAddHero, id)
                    break;
                }
                case ITEM_TYPE.EQUIPDATA: {
                    this.addEquip(item);
                    break;
                }
                case ITEM_TYPE.PROP: {
                    this.getOrUseItem(new RJXItem(item));
                    break;
                }
                case ITEM_TYPE.CURRENCY: {
                    this.getOrUseItem(new RJXItem(item));
                    break;
                }
                default:
                    break;
            }
        })
        this.saveEquip();
        this.saveItem();
    }

    // 获取或使用道具
    protected getOrUseItem(id: number | RJXItem, type?: number, num?: number) {
        let item: RJXItem;
        if (typeof id == "number") {
            item = new RJXItem([id, type, num])
        } else {
            item = id;
        }
        let chage = item.num;
        let key = KF.genItemKey(item.id, item.type);
        let items = this._itemData.get(key);
        if (!items) {
            items = [];
            this._itemData.set(key, items);
        }
        if (chage > 0) {
            if (items.length == 0) {
                let tpl = new RJXItem([item.id, item.type, 0]);
                // items.push(tpl);
                this.addItem(tpl);
            }
            while (chage > 0) {
                let last = items[items.length - 1];
                let maxNum = last.maxPile;
                let curNum = last.num;
                let subNum = maxNum - curNum;
                if (subNum >= chage) {
                    last.num += chage;
                    chage = 0;
                }
                else {
                    last.num += subNum;
                    chage -= subNum;
                    let item = new RJXItem([id, type, 0]);
                    this.addItem(item);
                }
            }
        }
        else if (chage < 0) {
            while (chage < 0) {
                if (items.length == 0) {
                    cc.warn('物品消耗不正确，不存在该物品');
                    break;
                }
                let last = items[items.length - 1];
                let curNum = last.num;
                if (curNum <= -chage) {
                    chage += curNum;
                    this.removeItem(last);
                    continue;
                }
                else {
                    last.num += chage;
                    chage = 0;
                }
            }
        }

        if (item.type === ITEM_TYPE.CURRENCY) {
            GCtrl.ES.emit(CMsg.client.bag.onCurrencyChange);
        }
    }

    protected addItem(id: number | RJXItem, type?: number, num?: number) {
        let item: RJXItem;
        if (typeof id == 'number') {
            item = new RJXItem([id, type, num]);
        }
        else {
            item = id;
        }
        let dataItems = this._itemData.get(item.key);
        if (!dataItems) {
            dataItems = [];
        }
        dataItems.push(item);
        this._itemData.set(item.key, dataItems);
    }

    protected removeItem(item: RJXItem) {
        item.num = INVALID_VALUE;
        let dataItems = this._itemData.get(item.key);
        let idx = dataItems.indexOf(item);
        if (idx != INVALID_VALUE) {
            dataItems.splice(idx, 1);
            if (dataItems.length == 0) {
                this._itemData.delete(item.key);
            }
        }
    }


    /***************************************************装备部分************************************ */
    protected saveEquip() {
        GameMgr.lOwnEquips.save(this._equipData);
    }

    public setIsFirstExp(insId) {
        let equip = this.getEquipDataById(insId);
        if (equip) {
            equip.isFirstExp = true;
            this._equipData.set(insId, equip);
            this.saveEquip();
        }
    }

    //通过id获取装备
    public getEquipDataById(id: string) {
        let equip = this._equipData.get(id);
        if (!equip) {
            cc.warn('can\'t find equip by id' + id);
            return
        }
        return equip
    }

    /**获取所有的装备 */
    public getAllEquips() {
        return this._equipData.values<REquireItem>();
    }

    /**获取装备与兵书 */
    public getHeroEquip(heroId: number): { equip: Array<string>, book: Array<string> } {
        let allEquips = this.getAllEquips();
        let equip = new Array<string>();
        let book = new Array<string>();
        for (let i = 0; i < allEquips.length; i++) {
            for (let j = 0; j < allEquips[i].itemData.raw.target.length; j++) {
                if (allEquips[i].itemData.raw.target[j] == heroId) {
                    equip.push(allEquips[i].insId);
                }
                if (allEquips[i].itemData.raw.target[j] == 0) {
                    book.push(allEquips[i].insId);
                }
            }
        }
        return { equip, book };
    }

    /**获取所有兵书 */
    public getAllBook(bool: boolean = true) {
        let allEquips = this.getAllEquips();
        let bookArr: Array<REquireItem> = [];
        let book: string[] = [];
        allEquips.forEach((v: REquireItem) => {
            let equipInfo = GameMgr.equipData.getRaw<SEquipDataRaw>(v.equipId);
            if (equipInfo.job == SQUAD_BUTTON.ALL) {
                bookArr.push(v);
            }
        })
        if (bookArr.length > 0) {
            //所有英雄热数据
            let allHero = GameMgr.rHeroData.getHaveHeros(SQUAD_BUTTON.ALL);
            // console.log('所有英雄热数据', allHero);
            if (bool) {
                allHero.have.forEach((v) => {
                    if (v.equips.length > 0) {
                        v.equips.forEach((equips, equipsIndex) => {
                            bookArr.forEach((book, bookIndex) => {
                                if (equips == book.insId) {
                                    bookArr.splice(bookIndex, 1);
                                }
                            })
                        })
                    }
                })
            }
            bookArr.forEach((v) => {
                book.push(v.insId);
            })
        }
        // console.log('bookArr', bookArr, book);
        return book
    }

    /**获取英雄身上所有的装备 */
    public getOwnerAllEquip(heroId: number): string[] {
        let allEquips = this.getAllEquips();
        let array = new Array<string>();
        for (let i = 0; i < allEquips.length; i++) {
            let equipInfo = GameMgr.equipData.getRaw<SEquipDataRaw>(allEquips[i].equipId);
            for (let j = 0; j < allEquips[i].itemData.raw.target.length; j++) {
                if ((equipInfo && allEquips[i].itemData.raw.target[j] == heroId) || (equipInfo && allEquips[i].itemData.raw.target[j] == 0)) {
                    array.push(allEquips[i].insId);
                }
            }
        }
        return array;
    }

    //获得装备
    protected addEquip(item: number[]) {
        let id = item[PART_ITEM.ID];
        for (let i = 0; i < item[PART_ITEM.NUM]; i++) {
            let insId = generateUid(6)
            let equip = new REquireItem([insId, id, 0, INVALID_VALUE]);
            this._equipData.set(insId, equip);
        }
    }

    /**添加合成装备 */
    protected AddSynthesisEquip(_, ynthesisEquip: SynthesisEquip) {
        let id = ynthesisEquip.id;
        let insId = null;
        let equip = null;
        for (let i = 0; i < ynthesisEquip.num; i++) {
            insId = generateUid(6);
            equip = new REquireItem([insId, id, ynthesisEquip.slv, INVALID_VALUE]);
            this._equipData.set(insId, equip);
        }
        GameMgr.jumpToMgr.jumpGoTo(VIEW_ID.strengthenView, equip, BLESSEND_INFO.synthesis);
    }

    /**移除装备 */
    protected delEquip(data, id: string) {
        this._equipData.delete(id);
        this.saveEquip();
    }

    protected onPutOnEquip(_, param: GParam) {
        let info = param.get<EquipPutInfo>();
        let equip = this._equipData.get(info.equipId)
        if (equip) {
            equip.wear = info.heroId;
            this._equipData.set(info.equipId, equip)
        }
    }

    protected onPutOffEquip(_, param: GParam) {
        let info = param.get<EquipPutInfo>();
        let equip = this._equipData.get(info.equipId)
        if (equip) {
            equip.wear = null
            this._equipData.set(info.equipId, equip)
        }
    }



    /**强化升級 */
    protected onAddEquipSlv(_, param: GParam) {
        let info = param.get<EquipAddInfo>()
        let equip = this.getEquipDataById(info.equipId);
        if (!equip) return;
        equip.sLv += info.exp;
        this._equipData.set(info.equipId, equip);
        this.saveEquip();
        equip.updateProp();
    }

    /**下一级强化属性 */
    public onNextEquip(_, param: GParam): MapWrap<number, number> {
        let info = param.get<EquipAddInfo>()
        let equip = this.getEquipDataById(info.equipId);
        if (!equip) return;
        let propts: MapWrap<number, number> = new MapWrap<number, number>();
        propts = equip.nextUpdateProp();
        return propts
    }

    /**上一级强化属性 */
    public ontopEquip(_, param: GParam): MapWrap<number, number> {
        let info = param.get<EquipAddInfo>()
        let equip = this.getEquipDataById(info.equipId);
        if (!equip) return;
        let propts: MapWrap<number, number> = new MapWrap<number, number>();
        propts = equip.topUpdateProp();
        return propts
    }
}
